package processes

import (
	"encoding/json"
	"fmt"
	"go_code/project01_basic/chapter15_qq/client/utils"
	"go_code/project01_basic/chapter15_qq/message"
	"io"
	"net"
	"os"
	"strconv"
	"strings"
	"time"
)

type UserProcess struct {
	Conn       net.Conn
	UserId     int
	NickName   string
	UserStatus int `json:"userStatus"`
}

func (u *UserProcess) Login() (err error) {
	//获取用户账号信息
	var userId int
	var userPwd string
	fmt.Println("输入用户id:")
	fmt.Scanf("%d\n", &userId)
	fmt.Println("输入密码:")
	fmt.Scanf("%s\n", &userPwd)

	//1.连接到服务器
	conn, err := net.Dial("tcp", "10.251.50.46:8889")
	if err != nil {
		fmt.Println("net.Dial err =", err)
		return err
	}
	defer conn.Close()

	//2.创建消息
	mes := &message.Message{}
	mes.Type = message.LoginMesType

	loginMes := message.LoginMes{
		UserId:  userId,
		UserPwd: userPwd,
	}

	//3.序列化消息
	data, err := json.Marshal(loginMes)
	if err != nil {
		fmt.Println("json.Marshal err=", err)
		return
	}

	mes.Data = string(data)

	//传递消息
	tf := &utils.Transfer{
		Conn: conn,
	}
	err = tf.Delivery(mes)
	if err != nil {
		fmt.Println("com.Delivery err=", err)
		return
	}

	//解析返回信息
	mes, err = tf.ReadPkg()
	//mes is nil
	var loginResMes message.LoginResMes
	if mes.Type == message.LoginResMesType {
		err = json.Unmarshal([]byte(mes.Data), &loginResMes)
	} else {
		fmt.Println("接收信息错误")
	}

	if loginResMes.Code == 200 {
		fmt.Println("登录成功")
		CurUser.Conn = conn
		CurUser.User.UserId = userId

		//开启后端服务进程
		go serverProcessMes(conn)
		time.Sleep(100 * time.Microsecond)
		//显示当前在线用户信息
		fmt.Printf("当前在线用户:")
		for _, v := range loginResMes.OnlineUsers {
			id, _ := strconv.Atoi(v[:3])
			user := &UserProcess{
				UserId:     id,
				NickName:   string(v[4:]),
				UserStatus: message.UserOnline,
			}
			AddLoginUser(id, user)
			if string(v[:3]) == fmt.Sprint(userId) {
				CurUser.User.UserName = string(v[4:])
				continue
			}
			fmt.Printf("%v\t", v[4:])
		}
		fmt.Println()
		ShowMenu()
	} else {
		fmt.Println("登录异常,异常码为:", loginResMes.Code, loginResMes.Error)
	}
	return
}

func (u *UserProcess) Register() (err error) {
	//获取注册信息
	var userId int
	var userPwd string
	var nickName string
	fmt.Println("输入用户id:")
	fmt.Scanf("%d\n", &userId)
	fmt.Println("输入密码:")
	fmt.Scanf("%s\n", &userPwd)
	fmt.Println("输入昵称:")
	fmt.Scanf("%s\n", &nickName)

	//1.连接到服务器
	conn, err := net.Dial("tcp", "10.251.50.46:8889")
	if err != nil {
		fmt.Println("net.Dial err =", err)
		return err
	}
	defer conn.Close()

	//2.创建消息
	mes := &message.Message{}
	mes.Type = message.RegisterMesType

	var registerMes message.RegisterMes
	registerMes.User.UserId = userId
	registerMes.User.UserPwd = userPwd
	registerMes.User.UserName = nickName

	//3.序列化消息
	data, err := json.Marshal(registerMes)
	if err != nil {
		fmt.Println("json.Marshal err=", err)
		return
	}

	mes.Data = string(data)

	//传递消息
	tf := &utils.Transfer{
		Conn: conn,
	}
	err = tf.Delivery(mes)
	if err != nil {
		fmt.Println("registerMes Delivery err=", err)
		return
	}

	//解析返回信息
	mes, err = tf.ReadPkg()
	//mes is nil
	var registerResMes message.RegisterResMes
	if mes.Type == message.RegisterResMesType {
		err = json.Unmarshal([]byte(mes.Data), &registerResMes)
	} else {
		fmt.Println("接收信息错误")
	}

	if registerResMes.Code == 200 {
		fmt.Println("注册成功,可以重新登录了")
		os.Exit(0)
	} else {
		fmt.Println("注册异常,异常码为:", registerResMes.Code, registerResMes.Error)
		os.Exit(0)
	}
	return
}

func (u *UserProcess) Offline() {
	//1.创建消息
	mes := &message.Message{}
	mes.Type = message.OfflineMesType

	OfflineMes := message.OfflineMes{
		UserId:   CurUser.User.UserId,
		UserName: CurUser.User.UserName,
	}

	//2.序列化消息
	data, err := json.Marshal(OfflineMes)
	if err != nil {
		fmt.Println("json.Marshal err=", err)
		return
	}

	mes.Data = string(data)
	//3.传递消息
	tf := &utils.Transfer{
		Conn: CurUser.Conn,
	}
	err = tf.Delivery(mes)
	if err != nil {
		fmt.Println("com.Delivery err=", err)
		return
	}
}

func (u *UserProcess) SendFile(filePath string) (err error) {
	//只读打开文件
	f, err := os.Open(filePath)
	if err != nil {
		fmt.Println("os.Open err:", err)
		return
	}
	defer f.Close()

	//发送一个表头，表示下面要发送文件
	c := strings.Split(filePath, "/")
	fileMes := &message.FileMes{
		UserId:   CurUser.User.UserId,
		FileName: c[len(c)-1],
	}
	data, err := json.Marshal(fileMes)
	if err != nil {
		fmt.Println("json.Marshal err=", err)
		return
	}
	mes := &message.Message{
		Type: message.FileMesType,
		Data: string(data),
	}
	tf := &utils.Transfer{
		Conn: CurUser.Conn,
	}
	err = tf.Delivery(mes)
	if err != nil {
		fmt.Println("com.Delivery err=", err)
		return
	}

	//从本文件中写数据，写给网络接收端。读多少写多少
	buf := make([]byte, 8192)
	for {
		n, err := f.Read(buf)
		if err != nil {
			if err == io.EOF {
				fmt.Println("文件发送成功")
			} else {
				fmt.Println("f.Read err:", err)
			}
			return err
		}
		//写到网络socket中
		_, err = CurUser.Conn.Write(buf[:n])
		if err != nil {
			fmt.Println("conn.Write err:", err)
			return err
		}
	}
}

func (u *UserProcess) ReceiveFile(fileMes string) (err error) {
	//接收文件
	file := &message.FileMes{}
	err = json.Unmarshal([]byte(fileMes), file)
	if err != nil {
		fmt.Println("json.Unmarshal err=", err)
		return
	}
	fmt.Println("开始接收", file.FileName, "文件:")
	fileName := "D:/APP/goproject/src/go_code/project01_basic/chapter15_qq/client/rec_file/" + CurUser.User.UserName + "_" + file.FileName
	//按照文件名创建新文件
	f, err := os.Create(fileName)
	if err != nil {
		fmt.Println("os.Create err:", err)
		return
	}
	defer f.Close()

	//从网络中读数据，写入本地文件
	buf := make([]byte, 8192)
	for {
		n, _ := u.Conn.Read(buf)

		//写入本地文件，读取多少写多少
		f.Write(buf[:n])

		if n < 8192 {
			fmt.Println("接收文件完成")
			return
		}
	}
}
